package com.auxiliary;

import com.myidis.entity.CIResult;


import java.util.ArrayList;

public class CICalculator
{

    private ArrayList<TimeSequence> LeadQuotaSet;
    /// <summary>
    /// 先行指标组
    /// </summary>


    private ArrayList<TimeSequence> CoinQuotaSet;
    /// <summary>
    /// 一致指标组
    /// </summary>

    private ArrayList<TimeSequence> LagQuotaSet;
    /// <summary>
    /// 滞后指标组
    /// </summary>

    private ArrayList<ArrayList<TimeSequence>> QuotaSetArrayList;
    /// <summary>
    /// 先行、一致、滞后指标组的集合
    /// </summary>

    public ArrayList<TimeSequence> getLeadQuotaSet() {
		return LeadQuotaSet;
	}

	public void setLeadQuotaSet(ArrayList<TimeSequence> LeadQuotaSet) {
		this.LeadQuotaSet = LeadQuotaSet;
	}

	public ArrayList<TimeSequence> getCoinQuotaSet() {
		return CoinQuotaSet;
	}

	public void setCoinQuotaSet(ArrayList<TimeSequence> CoinQuotaSet) {
		this.CoinQuotaSet = CoinQuotaSet;
	}

	public ArrayList<TimeSequence> getLagQuotaSet() {
		return LagQuotaSet;
	}

	public void setLagQuotaSet(ArrayList<TimeSequence> LagQuotaSet) {
		this.LagQuotaSet = LagQuotaSet;
	}

	public ArrayList<ArrayList<TimeSequence>> getQuotaSetArrayList() {
		return QuotaSetArrayList;
	}

	public void setQuotaSetArrayList(ArrayList<ArrayList<TimeSequence>> QuotaSetArrayList) {
		this.QuotaSetArrayList = QuotaSetArrayList;
	}

	public ArrayList<ArrayList<Double>> getWeightArrayList() {
		return WeightArrayList;
	}

	public void setWeightArrayList(ArrayList<ArrayList<Double>> weightArrayList) {
		WeightArrayList = weightArrayList;
	}

	private ArrayList<ArrayList<Double>> WeightArrayList;
    /// <summary>
    /// 先行、一致、滞后指标组中每个指标的权重
    /// </summary>

    private int timeRange = 0;
    private String springDay;
    private String start;
    private int frequency;

    /// <summary>
    /// 构造函数
    /// 本构造函数中先行，一致，滞后指标组合均为输入指标组合
    /// 默认指标权重为1
    ///  </summary>
    /// <param name="CoinQuotaSet">一致合成指数的输入指标组合</param>
    /// <param name="springDay">春节天数</param>
    public CICalculator(ArrayList<TimeSequence> CoinQuotaSet,String springDay)
    {
        this.LeadQuotaSet = CoinQuotaSet;
        this.LagQuotaSet = CoinQuotaSet;
        this.CoinQuotaSet = CoinQuotaSet;
        QuotaSetArrayList = new ArrayList<ArrayList<TimeSequence>>();
        QuotaSetArrayList.add(this.LeadQuotaSet);
        QuotaSetArrayList.add(this.LagQuotaSet);
        QuotaSetArrayList.add(this.CoinQuotaSet);

        this.springDay = springDay;
        this.WeightArrayList = new ArrayList<ArrayList<Double>>();

        for (int i = 0; i < QuotaSetArrayList.size(); i++)
        {
            ArrayList<Double> tempArrayList = new ArrayList<Double>();
            for (int j = 0; j < QuotaSetArrayList.get(i).size(); j++)
                tempArrayList.add(1.0);
            WeightArrayList.add(tempArrayList);
        }
    }
    /// <summary>
    /// 构造函数
    /// 默认指标权重为1
    /// </summary>
    /// <param name="LeadQuotaSet">计算先行合成指数的指标列表</param>
    /// <param name="CoinQuotaSet">计算一致合成指数的指标列表</param>
    /// <param name="LagQuotaSet">计算滞后合成指数的指标列表</param>
    /// <param name="springDay"春节天数></param>

	public CICalculator(ArrayList<TimeSequence> leadQuotaSet, ArrayList<TimeSequence> coinQuotaSet, ArrayList<TimeSequence> lagQuotaSet, String springDay)
    {
        this.LeadQuotaSet = leadQuotaSet;
        this.LagQuotaSet = lagQuotaSet;
        this.CoinQuotaSet = coinQuotaSet;
        this.start = lagQuotaSet.get(0).getStartDate();
        QuotaSetArrayList = new ArrayList<>();
        QuotaSetArrayList.add(leadQuotaSet);
        QuotaSetArrayList.add(coinQuotaSet);
        QuotaSetArrayList.add(lagQuotaSet);

        this.springDay = springDay;
        this.WeightArrayList = new ArrayList<ArrayList<Double>>();
        for (ArrayList<TimeSequence> aQuotaSetArrayList : QuotaSetArrayList) {
            ArrayList<Double> tempArrayList = new ArrayList<Double>();
            for (int j = 0; j < aQuotaSetArrayList.size(); j++)
                tempArrayList.add(1.0);
            WeightArrayList.add(tempArrayList);
        }

    }
/// <summary>
/// 构造函数，可输入权重
/// </summary>
/// <param name="LeadQuotaSet"></param>
/// <param name="CoinQuotaSet"></param>
/// <param name="LagQuotaSet"></param>
/// <param name="weightArrayList"></param>
/// <param name="springDay"></param>
    public CICalculator(ArrayList<TimeSequence> leadQuotaSet, ArrayList<TimeSequence> coinQuotaSet, ArrayList<TimeSequence> lagQuotaSet, ArrayList<ArrayList<Double>> weightArrayList,String springDay)
    {
        this.LeadQuotaSet = leadQuotaSet;
        this.LagQuotaSet = lagQuotaSet;
        this.CoinQuotaSet = coinQuotaSet;
        this.start = lagQuotaSet.get(0).getStartDate();
        QuotaSetArrayList = new ArrayList<>();
        QuotaSetArrayList.add(leadQuotaSet);
        QuotaSetArrayList.add(coinQuotaSet);
        QuotaSetArrayList.add(lagQuotaSet);
        this.springDay = springDay;
        this.WeightArrayList = weightArrayList;
        this.frequency = lagQuotaSet.get(0).getFrequency();
    }
    /// <summary>
    /// 检查序列是否所有的值均大于0
    /// </summary>
    /// <param name="ArrayList"></param>
    /// <returns></returns>
    private boolean IsGreaterThanZero(ArrayList<Double> ArrayList)
    {
        for(Double d : ArrayList){
            if (d > 0) continue;
            else return false;
        }
        return true;
    }


    /// <summary>
    /// 求指标标准化对称变化率
    /// </summary>
    /// <param name="Quota"输入指标></param>
    /// <returns></returns>
    private ArrayList<Double> NormQuota(TimeSequence timeSequence )
    {
        ArrayList<Double> values=new ArrayList<Double>(timeSequence.getValueList());
        ArrayList<Double> CArrayList = new ArrayList<Double>();//对称变换率
        CArrayList.add(0.0);
        for (int i = 1; i < values.size(); i++)
        {
            if(timeSequence.getQuotaDataType() == 1) //1不是比率数据,2是比率数据
                if(IsGreaterThanZero(values)) //没有非正数据
                    CArrayList.add(200*(values.get(i)-values.get(i-1))/(values.get(i)+values.get(i-1)));
                else
                    CArrayList.add(values.get(i)-values.get(i-1));
            else
                CArrayList.add(values.get(i)-values.get(i-1));
        }
        //标准化对称变换率
        //a:标准化因子
        Double a=0.0;
        for (Double d : CArrayList) {
            a += Math.abs(d);
        }
        a = a - CArrayList.get(0);
        a = a / (timeRange - 1);
        //  QIUDE标准化对称变换率
        ArrayList<Double> SArrayList = new ArrayList<Double>();
        //SArrayList.Add(0);
        for (Double d : CArrayList)
        {
            SArrayList.add(d / a);
        }
        return SArrayList;
    }

    /// <summary>
    /// 计算指标组的标准化平均变化率
    /// </summary>
    /// <returns></returns>
    private ArrayList<ArrayList<Double>> NormQuotaSet()
    {
        ArrayList<ArrayList<Double>> RArrayList = new ArrayList<ArrayList<Double>>();//指标组的平均变化率
        ArrayList<ArrayList<ArrayList<Double>>> SSetArrayList = new ArrayList<ArrayList<ArrayList<Double>>>();//所有指标的标准化变化率

        ///求子指标组合中权重的和
        ArrayList<Double> weightSumArrayList = new ArrayList<Double> ();
        for(ArrayList<Double> weightArrayList : WeightArrayList)
        {
            Double weight=0.0;
            for (Double d : weightArrayList)
                weight += d;
            weightSumArrayList.add(weight);

        }


        for(ArrayList<TimeSequence> ArrayListQuota : QuotaSetArrayList) //对先行，一致，滞后分别操作
        {

            //求指标的标准化平均变化率SArrayList
            ArrayList<ArrayList<Double>> SArrayList = new ArrayList<ArrayList<Double>>();//指标的标准化平均变化率
            for(TimeSequence timeSequence : ArrayListQuota)//对先行/一致/滞后中的每一个指标求S
                SArrayList.add( NormQuota(timeSequence)); //SArrayList存放每个指标的标准化变化率
            SSetArrayList.add(SArrayList);
        }

        int iterative = 0;
        for(ArrayList<ArrayList<Double>>  SArrayList : SSetArrayList)//由指标的标准化变化率求指标组的标准化平均变化率
        {
            //计算先行/一致/滞后指标组每一个时点上的平均变化率R
            int iterative2=0;
            ArrayList<Double> r    = new ArrayList<Double>();
            for (int i = 0; i < timeRange; i++)
                r.add(0.0);
            for (ArrayList<Double> dd : SArrayList) //求某个指标组的平均变化率r
            {
                for (int i = 1; i < timeRange; i++)
                {
                    r.set(i, r.get(i) + dd.get(i) * WeightArrayList.get(iterative).get(iterative2));
                    r.set(i, r.get(i) / weightSumArrayList.get(iterative));
                }
                iterative2 += 1;
            }

            RArrayList.add(r);
            iterative+=1;
        }

        ArrayList<Double> FArrayList = new ArrayList<Double>();//指数标准化因子
        Double R2 = 0.0;
        for(Double d : RArrayList.get(1))
            R2+=(Math.abs(d));
        for(ArrayList<Double> dd : RArrayList)
        {
            Double f=0.0;
            for (Double d : dd)
                f += Math.abs(d);
            FArrayList.add(f/R2);
        }
        ///标准化平均变化率VArrayList
        ArrayList<ArrayList<Double>> VArrayList = new ArrayList<ArrayList<Double>>();
        for(int i=0;i<RArrayList.size();i++)
        {
            ArrayList<Double> temp = new ArrayList<Double>();
            temp.add(0.0);
            for (int j = 1; j < RArrayList.get(0).size(); j++)
            {
                temp.add(RArrayList.get(i).get(j) / FArrayList.get(i));
            }
            VArrayList.add(temp);
        }
        return VArrayList;
    }

   /// <summary>
    /// 计算序列复利
    /// 首先调用BB算法，得到序列最初循环与最后循环，再计算复利
   /// </summary>
   /// <param name="dataArrayList">输入数据序列</param>
    /// <param name="start">输入数据序列的开始时间</param>
   /// <param name="springDay">春节天数</param>
   /// <returns></returns>
    private Double CI_Cominterest(ArrayList<Double> dataArrayList, String start,String springDay, int frequency)
    {

        BBForPeakValley bb = new BBForPeakValley(dataArrayList, start, springDay, frequency);
        int[][] TurnPoints = bb.calcExtremumByBB();
        ArrayList<Double> Array1 = new ArrayList<>();
        Array1 = (ArrayList<Double>)dataArrayList.clone();
        int length1 = TurnPoints.length;
        Double C1, C2;
        C1 = C2 = 0.0;
        int Start1, End1, Start2, End2;
        Start1 = End1 = Start2 = End2 = 0;

        if (length1 < 3)
        {
            Start1 = 0;
            End1 = Array1.size() - 1;
            Start2 = 0;
            End2 = Array1.size() - 1;
        }
        else
        {
            Start1 = TurnPoints[0][0];
            End1 = TurnPoints[2][0];
            Start2 = TurnPoints[length1 - 3][0];
            End2 = TurnPoints[length1 - 1][0];
        }

        for (int i = Start1; i <= End1; i++)
            C1 += Array1.get(i);
        for (int i = Start2; i <= End2; i++)
            C2 += Array1.get(i);
        C1 = C1 / (End1 - Start1 + 1);
        C2 = C2 / (End2 - Start2 + 1);

        //added by zhangxun@20071204 to ensure r is meaningful
        if(C1<=C2)
             if (C1 <= 0) {  C2 = C2 + (100 - C1);C1 =  100.00; }
         if (C1 > C2)
             if (C2<= 0) { C1 = C1 + (100 - C2);C2 = 100.00;  }



        double r = 0.0;
        int Dist = (End2 + Start2) / 2 - (End1 + Start1) / 2;
        if (Dist != 0)
            r = (Math.exp((Math.log((C2 / C1))) / Dist) - 1) * 100;
        return r;
    }

   /// <summary>
   /// 计算合成指数
   /// </summary>
   /// <returns></returns>
    public CIResult CalculateCI()
    {
        if (this.CoinQuotaSet.size() == 0) return null;
        if (this.LeadQuotaSet.size() == 0) LeadQuotaSet = this.CoinQuotaSet; //如果没有则以一致指标组代替
        if (this.LagQuotaSet.size() == 0) LagQuotaSet = this.CoinQuotaSet;
        this.timeRange = 0;

        for (ArrayList<TimeSequence> QuotaS:QuotaSetArrayList)
        {
            if (QuotaS == null) return null;
            for (TimeSequence indi : QuotaS)
                if (indi == null) return null;
                else if (indi.getValueList() == null) return null;
            if (this.timeRange == 0)
            {
                this.timeRange = QuotaS.get(0).getValueList().size();
            }
            for (TimeSequence indi :QuotaS)
                if (indi.getValueList().size() < this.timeRange)
                {
                    this.timeRange = indi.getValueList().size();

                }
        }



        //String start = this.CoinQuotaSet[0].TimeSequence.getStartDateString().Replace("M", "."); ;
        //problem unsolved
        //求指标组的标准化平均变化率
        ArrayList<ArrayList<Double>> VArrayList = this.NormQuotaSet();

        //求初始合成指数
        ArrayList<ArrayList<Double>> InitialCIArrayList = new ArrayList<ArrayList<Double>>();
        for (int j = 0; j < VArrayList.size(); j++)
        {
            ArrayList<Double> temp = new ArrayList<Double>();
            temp.add(100.0);
            for (int i = 1; i < timeRange; i++)
                  temp.add(temp.get(i-1) * (200 + VArrayList.get(j).get(i)) / (200 - VArrayList.get(j).get(i)));
            InitialCIArrayList.add(temp);
        }//初始合成指数计算结束

//        List<List<double>> InitialCIList = new List<List<double>>();
//        for (int j = 0; j < VList.Count; j++)
//        {
//            List<double> temp = new List<double>();
//            temp.Add(100.0);
//            for (int i = 1; i < timeRange; i++)
//                temp.Add(temp[i-1] * (200 + VList[j][i ]) / (200 - VList[j][i ]));
//            InitialCIList.Add(temp);
//        }//初始合成指数计算结束


        //趋势调整
        Double GoalTrend = 0.0;
        //对一致指标组的每个指标求目标增长率后计算目标趋势
        for(TimeSequence Quota : CoinQuotaSet)
        {
             GoalTrend = GoalTrend+ CI_Cominterest(Quota.getValueList(),start,springDay,Quota.getFrequency());
        }
        GoalTrend=GoalTrend/CoinQuotaSet.size();
        //计算先行一致滞后初始合成指数的平均增长率
        ArrayList<Double> RArrayList= new ArrayList<Double>();
        for(ArrayList<Double> dd : InitialCIArrayList)
        {

            RArrayList.add(CI_Cominterest(dd,start,springDay, frequency));
        }
        //对三个指标组的标准化平均变化率VArrayList做趋势调整
        for(int i=0;i<VArrayList.size();i++)
        {
            for (int j = 1; j< VArrayList.get(0).size(); j++)
            {
                VArrayList.get(i).set(j, VArrayList.get(i).get(j)+ GoalTrend - RArrayList.get(i)) ;

            }
        }
        //计算合成指标
        CIResult ciResult=new CIResult();
        ciResult.leadIndex.add(100.0);
        ciResult.coinIndex.add(100.0);
        ciResult.lagIndex.add(100.0);
        for (int i = 1; i < timeRange; i++)
        {
            //ciResult.leadIndex.Add( ciResult.leadIndex[i - 1] * (200 + VArrayList[0][i - 1]) / (200 - VArrayList[0][i - 1]));
            //ciResult.coinIndex.Add( ciResult.coinIndex[i - 1] * (200 + VArrayList[1][i - 1]) / (200 - VArrayList[1][i - 1]));
            //ciResult.lagIndex.Add( ciResult.lagIndex[i - 1] * (200 + VArrayList[2][i - 1]) / (200 - VArrayList[2][i - 1]));
            ciResult.leadIndex.add(InitialCIArrayList.get(0).get(i-1) * (200 + VArrayList.get(0).get(i)) / (200 - VArrayList.get(0).get(i)));
            ciResult.coinIndex.add(InitialCIArrayList.get(1).get(i-1) * (200 + VArrayList.get(0).get(i)) / (200 - VArrayList.get(0).get(i)));
            ciResult.lagIndex.add(InitialCIArrayList.get(2).get(i-1) * (200 + VArrayList.get(0).get(i)) / (200 - VArrayList.get(0).get(i)));
        }
        //最后的调整，使基准年份平均值为100
        Double LeadBase, CoinBase, LagBase;
        LeadBase = CoinBase = LagBase = 0.0;
        for (int i = 0; i < 12; i++)
        {
            LeadBase += ciResult.leadIndex.get(i);
            CoinBase += ciResult.coinIndex.get(i);
            LagBase += ciResult.lagIndex.get(i);
        }

        for (int i = 0; i < timeRange; i++)
        {
            ciResult.lagIndex.set(i,(ciResult.lagIndex.get(i) / LagBase) * 1200) ;
            ciResult.leadIndex.set(i,(ciResult.leadIndex.get(i) / LeadBase) * 1200);
            ciResult.coinIndex.set(i,(ciResult.coinIndex.get(i) / CoinBase) * 1200);
        }


        return ciResult;
    }
}